package ee.siimoliver.chat.server;

import java.util.HashMap;

import ee.siimoliver.chat.utils.ChatUtils;
import ee.siimoliver.chat.utils.Const;
import ee.siimoliver.chat.utils.RequestMethods;

public class HttpMessage {

	private HashMap<String, String> headers;
	private RequestMethods type;
	private String path;
	private HashMap<String, String> getParameters;
	private String httpVer;
	private String ipPort;
	
	public HttpMessage() {}
	
	public HttpMessage(byte[] input) {
		headers = parseByteInput(input);
	}
	
	public HttpMessage(byte[] input, String ipPort) {
		this.ipPort = ipPort;
		headers = parseByteInput(input);
	}

	private HashMap<String, String> parseByteInput(byte[] input) {
		HashMap<String, String> output = new HashMap<String, String>();
		String[] inputAsStrings = new String(input).split("\\r?\\n");
		String[] firstLine = inputAsStrings[0].split("\\s+");
		type = determineRequestType(firstLine[0]);
		int paramsSepPos = firstLine[1].indexOf("?");
		if (paramsSepPos != -1) {
			path = firstLine[1].substring(0, paramsSepPos);
		} else {
			path = firstLine[1];
		}
		if (type.equals(RequestMethods.GET)) {
			parseGetParameters(firstLine[1]);
		}
		httpVer = firstLine[2];
		String body = "";
		for (int i = 1; i < inputAsStrings.length; i++) {
			if (!inputAsStrings[i].trim().isEmpty()) {
				int keyEndPos = inputAsStrings[i].indexOf(":");
				if (keyEndPos != -1) {
					output.put(inputAsStrings[i].substring(0, keyEndPos).trim(), 
							inputAsStrings[i].substring(keyEndPos + 1).trim());
				} else {
					body += inputAsStrings[i].trim();
				}
			}
		}
		output.put(Const.REQUEST_BODY, body);
		return output;
	}
	
	private String readNextChars(char[] source, int from, int length) {
		StringBuffer sb = new StringBuffer();
		for (int i = from; i < from + length; i++) {
			sb.append(source[i]);
		}
		return sb.toString();
	}
	
	private void parseGetParameters(String request) {
		if (!Const.IS_CUSTOM_CODING) {
			request = ChatUtils.decodeString(request, Const.IS_CUSTOM_CODING);
		}
		getParameters = new HashMap<String, String>();
		StringBuffer sb = new StringBuffer();
		String key = "";
		int lookLength = Const.NBSP.length();
		char[] requestCharArray = request.substring(request.indexOf("?") + 1).toCharArray();
		for (int i = 0; i < requestCharArray.length; i++) {
			switch (requestCharArray[i]) {
			case Const.AMPERSAND:
				String next = readNextChars(requestCharArray, i, lookLength);
				if (next.equals(Const.NBSP)) {
					sb.append(" ");
					i += lookLength - 1;
				} else if (next.equals(Const.NWLN)) {
					sb.append("\n");
					i += lookLength - 1;
				} else {
					getParameters.put(key, sb.toString());
					sb = new StringBuffer();
				}
				break;
			case Const.EQUALS:
				key = sb.toString();
				sb = new StringBuffer();
				break;
			default:
				sb.append(requestCharArray[i]);
				break;
			}
		}
		getParameters.put(key, sb.toString());
	}
	
	public RequestMethods determineRequestType(String type) {
		try {
			return RequestMethods.valueOf(type);
		} catch (Exception e) {
			return RequestMethods.NONE;
		}
	}
	
	public HashMap<String, String> getHeaders() {
		return headers;
	}

	public RequestMethods getType() {
		return type;
	}

	public String getIpPort() {
		return ipPort;
	}
	
	public String getPath() {
		return path;
	}

	public String getHttpVer() {
		return httpVer;
	}

	public HashMap<String, String> getGETParameters() {
		return getParameters;
	}

	@Override
	public String toString() {
		return "HttpMessage [type=" + type + ", path="
				+ path + ", GETparams=" + getParameters + ", from=" + ipPort + ", headers=" + headers + "]";
	}

}
